---
title: "Protest and incumbent support: Evidence from a natural experiment in Ghana"
abstract: "How do protests shape incumbent support in lower-income democracies? Protests serve an accountability function by informing voters about government performance, but can also polarise opinion around pre-existing social and political identities. Leveraging an anti-government demonstration in Ghana that intersected an original survey in the field, we find that respondents interviewed immediately after the protest are more trusting and approving of the President. This effect is robust across multiple bandwidths, specifications, and placebo tests, and is driven by those who voted for the ruling party at the previous election. Our findings are consistent with theories of social identity and group threat, where supporters of an unpopular administration rally to their in-group's defence. By contrast, the protest does nothing to shift opposition voters' strongly negative prior beliefs. We show how anti-government protests can sometimes bolster incumbent support, extending the study of partisanship and identity politics to an understudied democratic context."
date: "This version: `r format(Sys.time(), '%d %B %Y')`"
output: 
 bookdown::pdf_document2:
toc: false
mainfont: SourceSansPro
fontsize: 12pt
geometry: margin =1.1in
numbersections: true
citations_package: none
link-citations: yes
linkcolor: blue
header-includes:
- \def\UrlBreaks{\do\/\do-\do?}
- \usepackage[default]{sourcesanspro}
- \usepackage[T1]{fontenc}
- \usepackage{setspace}\doublespacing
- \usepackage{float}
- \usepackage{caption}
- \usepackage[labelfont=bf]{caption}
- \captionsetup[figure]{font=scriptsize}
- \usepackage[margin=1.5cm]{caption}
- \captionsetup[table]{font=scriptsize}
- \usepackage{lscape}
- \usepackage{booktabs}
- \usepackage{graphicx}
- \newcommand{\beginsupplement}{\setcounter{table}{0}  \renewcommand{\thetable}{A\arabic{table}} - \setcounter{figure}{0} \renewcommand{\thefigure}{A\arabic{figure}}}
- \pagenumbering{gobble}
bibliography: /protests_CPS.bib
---

 >> **Word count: 9,856**

```{r setup, include=FALSE}

knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE)

library(dplyr)
library(fixest)
library(sjPlot)
library(ggplot2)
library(reshape2)
library(lubridate)
library(broom)
library(purrr)
library(gridExtra)
library(ebal)
library(kableExtra)
library(haven)
library(ggstats)

```

```{r load data}

rm(list=ls())

load("protests_CPS_data.RData")



```

\newpage

\pagenumbering{arabic}

# Introduction

Protests - public, extra-institutional expressions of dissent - are a core part of democratic society [@lipsky1968;@tilly2015]. Driven by the financial crash, rising anxiety about climate change, concerns about social discrimination and access to information technology, they have become significantly more frequent in democracies around the world [@clement2016;@barrie2021]. In lower-income and lower-capacity contexts, where incumbents hold significant electoral advantage, protests offer an important way for the public to express dissatisfaction [@harris2019]. We ask whether such anti-government protests causally affect incumbent support.

While a long-standing literature explores the emergence of protests and why some individuals participate in them [see, e.g., @finkel1989personal; @chong2014collective], we know far less about their consequences for public attitudes and behaviors [@ketchley2021unpopular; @wallace2014spatial;@mazumder2018persistent]. This is an important oversight, as elite responsiveness to protests build on perceptions that public opinion will shift in some way [@hutter2018responds; @wouters2017demonstrating; @barrie2024]. Few studies have analysed whether these shifts actually occur, and those that do produce mixed empirical results [@frye2019; @wallace2014spatial; @winters2014partisan; @sangnier2017protests; @reny2021]. Moreover, existing work focuses overwhelmingly on wealthy democracies or countries impacted by the Arab Spring, leaving significant geographic blindspots.

In this paper, we study how protests shape incumbent support in Ghana, a lower-income democracy. We do so by leveraging a multi-day demonstration against the government in September 2023, the Occupy Julorbi House protests, on incumbent support. This protest erupted in the midst of an original, independently organised, and pre-registered survey which we were already conducting in the country. This offers causal leverage to examine public opinion, using an unexpected event during survey design (UESD) [@munoz2020].

Our analysis indicates that survey respondents interviewed after the protest are *more* supportive of the government. In the days immediately following the event, both approval and trust in the President rise significantly compared to the pre-protest period. This is clearly contrary to the expectations of those participating in the anti-government protest, and runs against the limited pre-existing work on sub-Saharan Africa [e.g. @sangnier2017protests; @curtice2021]. When unpacking our results, we find significant variation by party support, with positive aggregate effects driven by those who voted for the ruling party in the previous general election. The protests in Ghana appear to have generated a strong partisan response among those already somewhat predisposed towards the incumbent; they had no effect on opposition supporters.   

These findings help us to further unravel the "*cognitive effects of protests*" [@wallace2014spatial, p. 433] and the different paths through which demonstrations can shape public opinion. Protests can be a source of *information*, providing signals of government competence by highlighting the salience or relatability of key issues [see @winters2014partisan; @sangnier2017protests; @valentim2021creating]. For others, they can prime *group identities* in relation to a given policy domain [e.g. @reny2021; @tertytchnaya2020electoral]. Protests might then increase support for the government by providing favorable new insights [see @frye2019] or by drawing disparate groups together around a shared concern, like national security [@el2020protests]. This is an effect comparable to the well-documented "*rally round the flag*" dynamics following shock events, like terror attacks or the onset of the Covid-19 pandemic [@geys2017; @eggers2022rallying; @harding2023terrorism]. 

Our results speak to a less studied path through which protest events shape public opinion. Anti-government protests are defined in explicit opposition to certain political groups and interests, leading the government's supporters to feel threatened and to "*rally*" around their shared partisan identity in response to a group threat [@tajfel1979individuals]. In contrast, opposition voters already possess negative evaluations of the government, do not gain new information from the protests, and so do not update their opinions. We provide evidence of these dynamics in Ghana, where the Occupy Julorbi House demonstrations may have reinforced a sense of belonging among disaffected, excluded, government voters. This also speaks to a growing literature on "negative partisanship", where party support can be galvanized by a dislike of, or threat from, political opponents [@asekere2022parochial]. This adds to a small literature on the significance of partisan identities in African political environments, moving beyond a predominant focus on Western Europe or the United States [e.g. @carlson2016finding; @harding2019; @stoecker2023partisanship]. 

Our research design also makes an empirical advance on existing efforts to causally identify the effect of protests on political attitudes. To date, this has proven very difficult to do, given the endogeneity that plagues political participation. The unexpected event during survey design (UESD) has predominantly focused on terrorist events [@munoz2020], but salient mass protests can also serve as a valid treatment [ e.g. @valentim2021creating]. We apply the design to a pre-registered survey which was personally organised by the authors, lending an unusual degree of confidence in its independence relative to the event under study. Our survey allows us not only to *identify* the effect of the protest on public opinion but also explore the underlying mechanisms shaping this outcome. In doing so, we join only a small group of studies using the UESD to study political behavior in Africa [e.g., @harding2023terrorism]. Many African democracies face considerable uncertainty and instability, where unexpected events carry a particular societal and political significance for both voters and elites [@riedl2012].

Our findings in Ghana likely speak to a wider set of country cases, and can contribute to more general theoretical and empirical debates. The country shares many similarities with other lower-income democracies, and the Occupy Julorbi House demonstrations are reminiscent of a broader trend toward anti-government protests across the continent [@arruda2021protests; @hughes2016protest], from concerns about cost of living pressures in Nigeria through to controversial tax changes in Kenya. We discuss several scope conditions to our results, particularly around Ghana's *lack* of state repression and unusually institutionalized party system [@stoecker2023partisanship]. Nonetheless, we join a growing body of literature, which uses Ghana as an empirical base to study much broader political phenomena [e.g. @weghorst2013; @harding2015; @nathan2019; @asunka2019; @ofosu2019; @brierley2020; @brierley2020a].

We begin by outlining the channels through which protests shape public opinion in greater depth (\@ref(theory)), before moving to introduce our case, research design, core estimates, and scrutiny of our identifying assumptions (\@ref(case) to \@ref(robustness)). We examine partisan polarization as one potential mechanism (\@ref(mechanisms)) and critically consider the external validity of our case (\@ref(externalvalidity)), before discussing the wider implications of our findings (\@ref(discussion)).

# Background {#theory}

## Protest and public opinion

We now have a very large literature, spanning sociology and political science, on the processes underpinning the emergence and evolution of protests. This work has emphasized the role of resources, organization, and opportunity structures in shaping the development and onset of social movements and protest politics [see, for example, @mccarthy1977resource; @tarrow2005new]. One branch has explored the individual-level cognitive dynamics underlying the decision to engage in protest, highlighting both rational cost-benefit calculations [e.g., @finkel1989personal] and the importance of personal values, beliefs, and emotions [e.g., @besley2019democratic; @kostelka2019s; @aytac2019]. Others have highlighted the role of information technology in making it easier for protesters to co-ordinate, particularly in lower-income settings [e.g. @christensen2018; @manacorda2020].

We know less, however, about the *consequences* of protest events. Only a small number of papers have focused on the effects of popular mobilization, despite these being of substantive theoretical relevance for many disciplines [@barrie2021]. Recent work has tended to focus on party responsiveness [@hutter2018responds], the beliefs of elected officials [@wouters2017demonstrating], and media attention [@jennings2019street] in the aftermath of protest events. There is also a literature specifically concerned with repression [see, e.g., @andirin2022measuring], surveillance [@beraja2023ai], and the trade-offs these pose to autocrats in the wake of mass demonstrations. 

Within this nascent literature, however, less attention has been paid to how protests shape the opinions and attitudes of the public [see @barrie2021; @wasow2020]. Initially, protests were viewed as manifestations of discontent among peripheral or minority groups, unimportant for the evolution of wider public opinion [see @zaller1992nature]. But protests can shape public opinion *directly*, through paths we discuss in detail below, and *indirectly*, through the reactions and responses of politicians and the media [@barrie2021; see, also, for example, @andrews2015group; @wouters2019; @barrie2024; @wasow2020]. @wasow2020, for instance, suggests activists can influence public opinion through agenda setting; the protest tactics they employ can shape how the media covers their protests, which in turn will influence mass opinion. The effect of protests thus becomes important, not only for downstream macro political consequences, but as a mechanism shaping political attitudes. 

## Protests provide information

How do protests shape public opinion? Existing literature points toward two direct channels: protests act as a source of *information*, and can prime *social identities*. 

For the first channel, protests provide *information* about government competence and performance, or raise the salience of particular issues [see @barrie2021,p.928]. This creates awareness of causes, and perspectives to which people were previously less informed [e.g. @stewart2012]. To the extent that events provide new and credible information, this will cause members of the public to update their prior beliefs.^[This is a standard model of Bayesian learning. See @dunning2019a for an extended discussion, and application with respect to political information and the importance of priors.] For example, there is evidence that protests about immigration [@carey2014;@branton2015] and climate change [@agnone2007;@bugden2020] can significantly increase their perceived importance among voters.

Aside from particular issues, information can also change how citizens perceive their government. Protests across Europe in the wake of the Great Recession acted as a mechanism to attribute blame, leaving citizens less satisfied with incumbents and less trusting of politicians in general [@bremer2020dynamics;@valentim2021creating]. Mass demonstrations in Brazil increased the salience of government incompetence, reducing attachments to the ruling party [@winters2014partisan]. In Egypt's first Presidential elections, protests bolstered support for candidates associated with the former (authoritarian) regime, as a consequence of the heightened salience of order, stability and security [@el2020protests; @ketchley2021unpopular]. And perhaps most relevant to our study, @sangnier2017protests found that proximity to social protests in 13 African states reduced political trust, with citizens using these events to extract new information about the actions of leaders and the country's fundamentals.^[Even in authoritarian contexts, protests can provide citizens with new information that shapes their attitudes. In Russia, for instance, @tertytchnaya2020electoral find that protests increased the salience, and awareness, of discontent with the regime. But new information does not always lead to negative updating. For example @frye2019, also in Russia, show that the decision to allow post-electoral protests to take place can itself increase trust in government, an effect largely driven by opposition supporters who update about the incumbent's decision not to repress.]

## Protests prime social identities

The second channel through which protests shape public opinion is based on the priming of *social identities*. Protests often make particular social groups salient, be they defined by class, race, gender, or partisanship. In some cases they prime a wide, inclusive in-group to which many can identify. For instance, by priming identities other than race, @mazumder2018persistent shows that whites from US counties, which experienced historical civil rights protests, were more likely to identify as Democrats and less likely to harbor racial resentment against blacks. Others, though, have raised concerns about the ways these counties varied, which make it difficult to identify long-run causal effects [@biggs2020].

Often, though, the identities primed by protests are narrower than this. Demonstrations are by definition defined *against* certain interests and groups, and this can be perceived as a *threat* among those who are excluded. This leads protests to be perceived differently by different groups, driving heterogeneous responses in political attitudes and beliefs. The tactics employed by protesters can also drive heterogeneous responses in public opinion. Turning again to the civil rights movement in the US, @wasow2020 found that non-violent black protest played a crucial role in seeding the agenda in favor of civil rights. In contrast, where there was protester-initiated violence, the issue was framed in the context of disorder by the media, and demonstrations were perceived as more dangerous by whites. Similarly, there is partisan variation in how recent Black Lives Matter protests are perceived, with white Republicans more likely to focus on violence and criminal activity [see: @reny2021; @drakulich2022; @boehmke2023]. Exposure to immigrant rights marches heightened feelings of trust and efficacy among some US Latino citizens, while driving political alienation for others [@wallace2014spatial]. There are also striking differences in how Democrats and Republicans recall the 2021 Capitol Hill riot [@calvillo2023]. 

In one of the only studies outside the United States, @selvanathan2019 study mass street demonstrations in Malaysia. They show that those experiencing empowerment in response to these protests reported greater identification with protesters and more support for wider political and institutional change. In contrast, those who experienced the protests as violent and threatening did not develop such an identification, and instead reported more support for the political status quo.

## What are we missing?

From this discussion, it is clear that there are divergent findings in the literature. Across different contexts, protests can both decrease and increase support for the government. This can operate through both informational and identity-based channels. And, given the endogeneity of political participation, these mixed findings may partly reflect the innate causal challenge of  isolating protests' effects on political attitudes.     

It is also evident that nearly all current work explores the effect of protests in either the US, Western Europe *or* authoritarian contexts.^[@selvanathan2019 and @sangnier2017protests are two exceptions, though the latter use a thirteen country sample containing several non-democracies.] We don't know whether these general findings, or mechanisms, travel to lower income *democratic* states, countries in which the median global citizen lives. This is particularly important, given these are often the contexts in which we witness the highest levels of protest, especially those that are anti-government [@harris2019]. And in the small body of work on these environments, there is an overt focus on information channels but a lack of attention on partisan divides, and how they may foster a divergent response. 

We try to address some of these gaps, by studying the effect of protests in a low capacity democratic context and offering a level of causal identification that goes beyond most existing work. We establish whether Ghana's Occupy Julorbi House protests increased or decreased support for the incumbent, and use our pre-registered survey to explore *who* is driving these effects. Taken together, our design offers us the opportunity to extend the findings from advanced industrial democracies to a globally important, but contextually different, type of state. 


# The case {#case}

## Politics and protest in Ghana

We study the impact of protest on public opinion in Ghana, a country with a competitive democracy but growing levels of protest, partly in response to deteriorating economic conditions. 

Ghanaian politics is dominated by two political parties: the New Patriotic Party (NPP) and New Democratic Congress (NDC) [@osei2013]. Since the formation of the Fourth Republic in 1992, the NPP and NDC have oscillated in and out of the Presidency, with four peaceful handovers of power as of 2025. At the time of our survey (2023) the NPP was in power, led by President Nana Akufo-Addo, but his government was widely unpopular and already expected to lose the next election [@aikins2023; @brooke-holland2024b]. Figure \@ref(fig:ghana-votes-plot) presents historic vote shares from Presidential elections since 2000, alongside voter intention figures from the most recent round of the Afrobarometer, a nationally representative survey. These figures proved largely accurate, with the NDC reclaiming office in a landslide victory in December 2024, and the NPP receiving one of its lowest ever vote shares.

```{r ghana-votes-plot, fig.cap="Electoral competition in Ghana. Panel (a) plots Presidential vote shares for the country's two largest parties, between 2000 and 2020. Panel (b) plots intended vote choice in the 2024 election, using data from round 9 of the Afrobarometer survey fielded in 2022.", fig.width=10, fig.height=4}

pol1 <- ggplot(agg_election, aes(x=election, shares, col=party)) +
  geom_point(alpha=0.7) + geom_line() +
  theme_bw() +
  scale_y_continuous(limits=c(25,79), breaks=c(25,50,75),
                     labels = c("25%", "50%", "75%")) +
  scale_x_continuous(breaks = c(2000, 2004, 2008, 2012, 2016, 2020)) +
  scale_colour_manual(values=c("darkgreen", "darkblue")) +
  ylab("Vote share") +
  ggtitle("a) Presidential election results (2000-2020)") +
  theme(legend.title = element_blank(), 
        legend.position = "bottom", 
        axis.title.x = element_blank())


## Vote intention (Afrobarometer r9)

pol2 <- AB_r9 %>%
  filter(!is.na(vote2024)) %>%
  ggplot(aes(x=vote2024, fill=vote2024, y = after_stat(prop)*100)) +
  geom_bar(stat="prop", position="dodge", alpha=0.9, col="black") +
  scale_fill_manual(values=c("darkgreen", "darkblue", "darkgrey")) +
  ylab("Share of respondents") +
  ggtitle("b) 2024 voter intention (Afrobarometer R9 - 2022)") +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(), 
        axis.title.x = element_blank())

grid.arrange(pol1, pol2, nrow=1)

```

While the government's unpopularity was multifaceted, one important factor is the country's declining economic conditions. While Ghana has seen significant development since the 1990s, fueling a reputation as a poster child for structural adjustment, this has faded in recent years [@bleck2018a]. The Covid-19 pandemic, agricultural shocks triggered by the Russia-Ukraine war, and unusually high levels of government debt have caused inflation to skyrocket in the country. The IMF estimates that the cost of basic goods rose by 42.2% in 2023 alone [@medina2024]. Meanwhile, the Ghana Cedi has been progressively devalued over the past decade, significantly raising the price of imports [@amoah2017]. In 2022 the government sought an IMF bailout, and associated conditionality, to aid economic recovery. This is despite the President promising repeatedly that Ghana was "beyond aid" when running for election, while heavily criticising previous governments for taking money from the fund [@donkor2024]. 

Given its competitive democracy and declining economy, it is perhaps unsurprising that Ghana has seen an uptick in the incidence of protest. Figure \@ref(fig:ghana-acled) provides evidence that protests have become more common across Ghana and Africa as a whole. One way Ghana differs, however, is that the incidence of violent protest, defined as those exhibiting "*excessive use of force against participants*" by ACLED, remains low. Peaceful protests are the norm, and while large-scale nationally salient protests don't happen often, there is nothing unusual about the concept of public gatherings to further a cause [@asante2018; @noll2023]. This is likely a reflection of the country's relatively strong protections for free speech and assembly. It suggests, however, that if public opinion shifts in response to a protest, it is unlikely to be driven by perceptions that the state "allowed" it to go ahead. This is clearly different from more authoritarian environments [@frye2019], helping us rule out this alternative explanation. 

\medskip 

```{r ghana-acled, fig.height=4, fig.width=8, fig.cap = "Protest incidence in Africa and Ghana. Data taken from ACLED, filtered for protests. Violent classified as events involving use of excessive force against participants. Trend lines suggest that both types of protest have become more common across the continent, but in Ghana this is driven by peaceful events."}

ggplot(data=acled_full, aes(x=YEAR, y = count_protests_log, col=type)) +
  facet_wrap(~sample, scales="free_y") +
  geom_smooth(method="glm") +
  geom_point(alpha=0.7, size=0.5, col="darkgrey") +
  scale_colour_manual(values = c("darkorange", "darkblue")) +
  theme_bw() +
  ylab("Log (event count + 1)") + xlab("Year") +
  theme(legend.position = "bottom", 
        legend.title = element_blank()) +
  ggtitle("Protests have increased in Ghana, but are usually peaceful (ACLED)")

```

## The Occupy Julorbi House protests

We study the Occupy Julorbi House protests, a multi-day, anti-government demonstration that took place from the 21st to 23rd September 2023. Protesters sought to bring attention to Ghana's high cost-of-living, poor public services, and government corruption. Starting in central Accra, participants marched toward and sought to "*occupy*" Jubilee House - the official seat of Ghana's President. The phrase "*Julorbi House*" is itself a play on words, using the expression "*julor bi*", which means "*child of a thief*", in the local Ga language. 

The protest was organised by activists from the *#FixTheCountry* movement, a pressure group that seeks to bring attention to governance failures in Ghana.^[See: https://fixthecountrygh.com/ (accessed 8th Dec 2023).] This was largely done online, with organisers citing a range of concerns including economic mismanagement, under-resourced public services, the country's "*deplorable road network*", its "*crumbling education system*", and illegal mining ("*galamsey*"). While relatively vague, the protestors made several demands to address these issues, such as a "*halt on borrowing and a plan for economic growth*", a "*review and restructuring of taxes*", a "*plan for fixing major roads*", and "*better and more adequate health care*".^[See: https://occupyjulorbihouse.my.canva.site/ (accessed 14th Jan 2025).] These largely represent "valence" or "competence" issues linked to the economy, on which opposition parties would likely agree with the protesters and point blame at the incumbent [@bleck2013].^[This is not true for all issues. For instance, the group also demanded the withdrawal of Ghana's controversial anti-LGBT law, a measure nominally supported by both major parties. Nonetheless, the economy, cost of living, and corruption were clearly overarching focus of the protest and media coverage surrounding it.]

The protest itself quickly became salient in national discourse, featuring in both domestic and international media outlets.^[For example: @amoah2023; @adom2023; @mensah2023; @kokoroko2023.] It was discussed extensively over local radio services across Ghana, was live streamed on Youtube and other social media platforms, and likely spread through word-of-mouth conversations. Many local celebrities took part, including well-known musicians, actors and models [@amoah2023], raising its prominence further. 

We provide systematic evidence of the protest's rapid salience in Figure \@ref(fig:google-trends-plot). Panel (a) presents daily mentions of the protest on Twitter/X, from the 1st August to 31st October 2023. Across the three protest days, the terms, "*Occupy Julorbi House*" and "*Fix the country*", were collectively mentioned more than 840,000 times. In the six weeks prior to the protest, there were fewer than 300 mentions on average per day. The eve of the protest saw 2,858 mentions, rising to 212,281 just 24 hours later, an increase of more than 7,400 per cent.^[These figures are sourced from Sprinklr, a market research company that provides access to social media salience data.]  

Panel (b) presents aggregated weekly data from Google Trends, from the 1st January to 31st October. Here we present results for the more generic search term "*protest*", and again find a rapid rise in salience in the week that the event took place. Google provides data on the relative frequency of search terms, on a scale from 0-100. We find this measure increases five-fold, from 19 to 100, between the week of the protest and the week immediately before.

\bigskip

```{r google-trends-plot, fig.width = 10, fig.height = 4, fig.cap = "Salience of the protest."}

salience1 <- ggplot(data=trends, aes(x=week, y=salience)) +
  geom_vline(aes(xintercept = lubridate::as_date("2023-09-17", format="%Y-%m-%d")), 
             col="darkorange", size=1.2, alpha=0.8) +
  geom_label(label="Protest days", col="black",
             x=as_date("2023-09-10", format="%Y-%m-%d"), y=110) +
  geom_line(size=1) +
  theme_bw() +
  scale_y_continuous(limits=c(0,120), 
                     breaks = c(0, 25, 50, 75, 100)) +
  ylab("Salience (weekly)") +
  xlab("Date (2023)") +
  ggtitle("b) Weekly salience on Google Trends")

options(scipen=999)

salience2 <- ggplot(tweets, aes(y=mentions, x=date_clean)) +
  annotate("rect", 
           xmin=as_date("2023-09-21", format="%Y-%m-%d"), 
           xmax=as_date("2023-09-24", format="%Y-%m-%d"), 
           ymin=0, ymax=Inf, 
           fill="darkorange", alpha=0.4) +
  geom_line(size=1, col="black") +
  xlab("Date (2023)") + ylab("Mentions (daily)") +
  theme_bw() +
  geom_label(label="Protest days", col="black",
             x=as_date("2023-09-23", format="%Y-%m-%d"), y=400000) +
  ggtitle("a) Daily mentions on Twitter/X") +
  scale_y_continuous(limits=c(0,425000))

grid.arrange(salience2, salience1, nrow=1)


```

\bigskip 

While not party political, the protest was nonetheless lauded by opposition actors. Ghana's then main opposition, the NDC, condemned the arrest of a small number of protesters, casting the government's response to the demonstration as "*a massive step backwards for our democracy*" [@citinewsroom2023]. In response, a spokesman for the ruling party claimed that the protest was in fact arranged by the NDC Presidential candidate, John Mahama [@3news2023]. In reality there were very few arrests made at the protests, and no evidence that the NDC provided explicit organisational assistance.

The protests also adopted harsh and emotional language to describe the incumbent, which may have been perceived as a partisan attack. This included emotional rhetoric around the "*moral decay*" of the administration, claims that "*every institution of this country is captured and co-opted*", and tacit threats that "*we don’t want to engage in violence, but if they push us to the wall, we have no other option*" [@adattor2023]. We examine partisan group threat in section \@ref(mechanisms), where we explore heterogeneity in response to the protests.

Unlike other mass demonstrations, the protest ended after three days without any clear concessions being made by the government. As seen in figure \@ref(fig:google-trends-plot), salience rapidly drops off after the main three day period, suggesting the Julorbi House demonstrations did not lead to immediate political action. In the longer term, however, there is some evidence that the protests served as a focal point for future mobilisation, and may reflect, or even have exacerbated, growing party polarisation across the country. The government organised its own pro-incumbent demonstration in December [@osei2023], while a follow-up to the Julorbi House protests in September 2024 saw participants set fire to NPP flags [@ghanaweb2024].

# Research design {#rd}

## The unexpected event during survey design {#uesd}

We use the Occupy Julorbi House protests to study how protests shape public opinion. We leverage the fact that the demonstration intersected a distinct pre-registered survey being fielded by the authors. This allows us to compare outcomes measured immediately before and after, adopting an *unexpected event during survey design* (UESD) [@munoz2020].

We fielded a survey in three regions across Ghana, mapped in Figure \@ref(fig:print-map), as part of a distinct project studying financial remittances and petty corruption. Our survey questionnaire captures various measures of government support, voting behavior, and baseline demographic characteristics, which we use to trace the impact of the protest. In this paper, we use responses from two regions, Greater Accra and Bono, with a total sample of 901. We drop responses from Central region, as fieldwork began later in this part of the country leaving too few pre-protest interviews.^[Fieldwork in Central region started later due to enumerator illness, leaving very few responses in the pre-protest period (N=40) and significant demographic imbalance.]

```{r survey map, include=FALSE}

library(sf)
library(tmap)

map <- ggplot(ghana_adm, aes(fill=sample)) +
  geom_sf(lines="black") +
  scale_fill_manual(values = c("darkred", "pink", "white")) +
  theme_blank() +
  theme(axis.text = element_blank(), 
        legend.title = element_blank(),
        legend.text=element_text(size=6))


```

```{r print-map, fig.width=4, fig.height=3, fig.cap="Map of areas sampled in the survey."}

map

``` 

### Survey timing

Identification stems from the independence of our survey timing. Whether a respondent is interviewed before or after the protest is arbitrary, and so differences between these groups reflect the short-run causal impact of the demonstration. This entails a series of *ignorability* and *excludability* assumptions, which we scrutinize in detail in section \@ref(robustness). 

We are confident that the timing of our survey was unrelated to the protest. Fieldwork was initially scheduled to start on the 11th September, though logistical constraints around university financing delayed this by one week. We trained survey enumerators on the 15th September, the same day we registered our pre-analysis plan, and the survey began on Monday 18th. We had no prior knowledge that the Julorbi House protests would take place. Figure \@ref(fig:survey-distribution) plots the temporal distribution of survey responses. The interviews took place between the 18th and 29th September, with the protests erupting on the 21st, 22nd and 23rd, in the middle of our fieldwork. 

\medskip

```{r survey-distribution, fig.height=4, fig.width=8, fig.cap="Temporal distribution of interviews around the protest."}

### Histogram of events by day

julorbi_hist <- data %>% group_by(date) %>%
  select(date, postJulorbi, postJulorbi3days) %>%
  mutate(duringJulorbi = ifelse(date >= lubridate::as_date("2023-09-21", format="%Y-%m-%d") &
                                 date <= lubridate::as_date("2023-09-23", format="%Y-%m-%d"), 
                              1, 0),
         duringJulorbi = ifelse(is.na(duringJulorbi) == TRUE, 1, duringJulorbi),
         postJulorbi = ifelse(is.na(postJulorbi) == TRUE, 1, postJulorbi),
         group = factor(ifelse(postJulorbi == 0, "Pre-period (N=234)",
                          ifelse(duringJulorbi == 1, "Protest days (N=266)", "Post-period (N=401)")),
                          levels = c("Pre-period (N=234)", "Protest days (N=266)", "Post-period (N=401)")))

bal1 <- ggplot(data=julorbi_hist, aes(x=date, group = date, col=factor(duringJulorbi),
                      fill = factor(group))) +
  geom_bar(col="black") +
  scale_x_date(date_labels = "%d", 
               date_breaks = "1 day") +
  theme_bw() +
  scale_fill_manual(values = c("grey10", "darkred", "grey80")) +
  theme(legend.title=element_blank(), 
        legend.position = "bottom") +
  ylab("Count") + xlab("Date (Sep 2023)") +
  labs(title = "Distribution of survey responses around the protests")

bal1

```

Following best practice, we compare respondents at various bandwidths around the event, which are summarized in Table \@ref(tab:bandwidth-table). This covers those interviewed two and three days before and after the protests, alongside the full sample, dropping protest days themselves. To increase observations, we also use an alternative bandwidth in which we only drop the first day of the protest, on the assumption that this triggered the largest "shock" for voters. We note, however, that in UESDs a narrower bandwidth does not necessarily provide inferential advantage, as identifying variation stems from the full range of survey dates rather than a "local" cutoff. If anything, a wider window increases statistical power, and so may help to estimate effects more precisely [@munoz2020].

```{r bandwidth-table, results="asis"}

col1 <- c("2 days", "3 days", 
          "Full ex. all protest days", "Full ex. first protest day")
col2 <- c("19-20 Sep", "18-20 Sep", "18-20 Sep", "18-20 Sep")
col3 <- c("24-25 Sep", "24-26 Sep", "24-29 Sep", "22-29 Sep")
col4 <- c("21-23 Sep", "21-23 Sep", "21-23 Sep", "21 Sep")
col5 <- c(343, 515, 632, 802)

bw <- data.frame(cbind(col1, col2, col3, col4, col5))
colnames(bw) <- c("Bandwidth", "Pre", "Post", "Excluded", "Sample")

kable(bw, 
      format = "latex", booktabs = TRUE, 
      caption = "Bandwidths used in the UESD.") %>%
  row_spec(0, bold=T) %>%
  kable_styling(latex_options = "hold_position")


```


### Sample selection and balance

Survey respondents were selected through a multi-stage randomization process, in which districts and tracts were randomly selected using census data. Within each tract, respondents were selected by enumerators using a random walk protocol. Ten interviews took place in each community, and there were no call-backs.^[We have an odd number of total respondents (901), as we received data from eleven respondents in one community. This is likely a simple mistake on the part of the enumerator.] Where possible, all interviews were conducted in a single day. Given our survey's intended focus, we adopted a quota system to over-sample those receiving financial remittances from relatives. This was successfully implemented, with 50.9% of our sample receiving some form of remittance. More detailed information about our sampling strategy can be found in the supplementary materials, while we formally compare our sample characteristics to a recent nationally representative survey in section \@ref(externalvalidity).

In Figure \@ref(fig:covariate-plot-bivariate) we compare the demographic composition of respondents interviewed before and after the protest, across each bandwidth, by region. We include both remittance receipt (our quota selected outcome) alongside age, gender, education, vote choice in the previous election, and whether a respondent lives in, or was born in, an urban area. As is common in UESD settings, there are some differences between groups. Respondents interviewed after the protest are more likely to live in an urban area, while at some bandwidths they are slightly better educated. In Greater Accra, some groups are less likely to have been born in a town or city, and slightly more likely to have voted for the ruling party. In Bono, respondents are generally better balanced across these characteristics.

\medskip 

```{r covariate-plot-bivariate, fig.height=6, fig.width=8, fig.cap = "Bivariate balance plots, comparing respondents interviewed before and after the protests (as defined by bandwidth)."}

### Balance checks

data_bal <- data %>% mutate(
         duringJulorbi = ifelse(date >= lubridate::as_date("2023-09-21", format="%Y-%m-%d") &
                                 date <= lubridate::as_date("2023-09-23", format="%Y-%m-%d"), 
                              1, 0),
         postJulorbi_donut = ifelse(duringJulorbi == 1, NA, postJulorbi),
                        GA = ifelse(region == "Greater Accra", 1, 0),
                        bono = ifelse(region == "Bono", 1, 0)) %>%
  mutate(age_std = as.numeric(scale(age)),
         male_bin = ifelse(gender == "Male", 1, 0),
         urbrur_bin = ifelse(urbrur == "Urban", 1, 0), 
         urbrur_from_bin = ifelse(urbrur_from == "Urban", 1, 0),
         education_none = ifelse(education == "None", 1, 0),
         education_school = ifelse(education %in% c("Primary", "Secondary"), 1, 0),
         education_university = ifelse(education == "University", 1, 0), 
         govt_bin = ifelse(vote2020_inc == "Govt", 1, 0),
         opp_bin = ifelse(vote2020_inc == "Opp", 1, 0),
         nonvote_bin = ifelse(vote2020_inc == "Non-voter", 1, 0))

## Split by region

data_ga <- data_bal %>% filter(bono == "0")
data_bono <- data_bal %>% filter(bono == "1")

## Run balance tests (bivariate)

balance1ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi, data=data_ga)

balance2ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi_donut, data=data_ga)

balance3ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi3days, data=data_ga)

balance4ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi2days, data=data_ga)

balance1bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi, data=data_bono)

balance2bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi_donut, data=data_bono)

balance3bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi3days, data=data_bono)

balance4bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        govt_bin, nonvote_bin,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi2days, data=data_bono)


## Make graph

balance_list <- c(balance1ga, balance2ga, balance3ga, balance4ga,
                  balance1bono, balance2bono, balance3bono, balance4bono)

balance_df <- map_df(balance_list, broom::tidy, .id="model") %>%
  filter(term != "(Intercept)") %>%
  mutate(conf.low = estimate - 1.96*std.error,
         conf.high = estimate + 1.96*std.error,
         sample = ifelse(term == "postJulorbi", "Full ex. first protest day", 
                  ifelse(term == "postJulorbi_donut", "Full ex. all protest days", 
                  ifelse(term == "postJulorbi3days", "3 day bandwidth pre/post", 
                         "2 day bandwidth pre/post"))),
         outcome = rep(c("Age (standardised)", "Remittances",
                         "Gender (male)", 
                         "No formal education", "Primary/secondary education", "University education",
                         "Voted Govt", "Turnout",
                         "Urban", 
                         "Born urban"), 8), 
         region = rep(c("Greater Accra", "Bono"), each=40))

bal2 <- ggplot(data=balance_df, aes(x = estimate, 
                                    y = factor(outcome,
                                               levels = c(
                                               "Urban",
                                               "Born urban",
                                               "Turnout", "Voted Govt",
                                               "No formal education", "Primary/secondary education",
                                               "University education",
                                               "Gender (male)",
                                               "Remittances",
                                               "Age (standardised)")))) +
  facet_wrap(~factor(sample, 
                     levels = c("2 day bandwidth pre/post",
                                "3 day bandwidth pre/post", 
                                "Full ex. all protest days",
                                "Full ex. first protest day"))) + 
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low, xmax=conf.high, height=0, width=0, col=region),
                 position = position_dodge(width=0.5)) +
  geom_point(position = position_dodge(width=0.5), alpha=0.7, aes(col=region, shape = region)) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(),
        axis.title.y = element_blank()) +
  xlab("Difference before/after protest") +
  ggtitle("Covariate balance tests before/after the protests") +
  scale_x_continuous(limits = c(-0.6, 0.6)) +
  scale_colour_manual(values = c("darkorange", "darkblue"))

bal2

```

These differences reflect wider regional heterogeneity in our sample. In Bono, which is predominantly rural, enumerators began in more remote locations and worked their way *towards* towns and cities. In Greater Accra, the handful of rural communities on the city's edge happened to be interviewed in the first few days of fieldwork. In both cases, however, several enumerators were working across multiple sites, meaning that both urban and rural individuals were interviewed on each day. Figure \@ref(fig:urban-plot) plots the temporal distribution of urban and rural respondents in our sample. Given greater urbancy, it is unsurprising that we observe slightly higher education levels in the post-treatment period. 

It is also important to note that urban or educational imbalance is likely to bias *against* the positive effects we go on to estimate. In Ghana, like most of Africa, urban and better educated respondents tend to be *less* supportive of incumbent governments [@harding2020]. If urban/rural compositional differences drive our UESD estimates, we would therefore expect the presence of more urban respondents in the post period to lead to negative effects overall.

Nonetheless, we present specifications that adjust for all of the above characteristics, as a vector of controls or through entropy balancing, and our results are consistent across baseline and adjusted models. More generally, our discussion of balance relates to the *ignorability* assumption underpinning the UESD, which we scrutinise further in section \@ref(ignorability).

\medskip 

```{r urban-plot, fig.height=4, fig.width=8, fig.cap="Distribution of urban and rural survey respondents over time, broken by region. Bono is primarily rural Ghana and Greater Accra primarily urban. Positive urban imbalance is likely driven by the chance sampling of Bono's small urban population after the protest, and Greater Accra's small rural population before it."}

urbrur_summary <- data %>% 
  group_by(region, urbrur, date) %>%
  summarise(out = n()) %>%
  mutate(date = lubridate::as_date(date, format="%Y-%m-%d"))

ggplot(urbrur_summary, aes(x=date, y=out, col=urbrur)) +
  facet_wrap(~region) +
  geom_point() +
  geom_line() +
  theme_bw() +
  xlab("Date") + ylab("Count") + 
  theme(legend.title=element_blank(), 
        legend.position="bottom") +
  scale_colour_manual(values = c("orange", "darkblue"))
  

```


### Outcomes

We study two key outcomes relating to government support: trust and approval in the President. In our survey, we included standard questions from the Afrobarometer, which gauge trust and approval. With reference to the President, respondents were asked "*how much do you trust each of the following?*" and "*do you approve or disapprove of the way that the following people have performed their jobs over the past 12 months?*". Both are measured on a 1-4 scale, where higher values indicate greater support. 

Given Ghana's negative macroeconomic climate, cost-of-living concerns and the incumbent's long tenure, baseline support is unsurprisingly low. Among pre-protest respondents, mean trust and approval are at 1.65 and 1.69 on their respective 1-4 point scales. 

## Specification

We estimate the impact of the protest using ordinary least squares. For individuals $i$ in regions $r$, we measure differences in outcomes before and after the protest, with $\text{post}_{ir}$ a binary indicator equal to 1 for post-period respondents: 

\begin{equation} 
y_{ir} = \delta \text{post}_{ir} + \gamma X_{ir} + \phi_r + \epsilon_{ir}
\end{equation}

We estimate three specifications. At baseline, we include region fixed effects ($\phi_r$) to account for contextual differences between Greater Accra and Bono. Second, we account for observable individual-level characteristics by controlling for a vector of demographic covariates ($\gamma X_{ir}$).^[We follow @harding2023terrorism and use a respondent's age, gender, education, and urbancy. We also control for whether or not a respondent was part of our remittance quota, as well as vote choice in the previous general election. We do not use any attitudinal measures, due to the risk of post-treatment bias. While @harding2023terrorism also control for religion, we do not ask about this in our survey, though do not see it as being as relevant to our research question.] Third, we pre-processes the data with entropy balancing [@hainmueller2012].^[In these specifications, we re-code education and 2020 vote choice as continuous variables. For education, higher values indicate higher levels of educational attainment. For vote choice, -1 indicates the opposition, 1 the government, and 0 those who do not know their vote or did not participate.] Following best practice, we present results from all three specifications across multiple bandwidths [@munoz2020].

# Results {#results}

## Trust and approval {#mainresultsplot}

Figure \@ref(fig:results-baseline-trust-and-approval) presents our main results. These show the aggregate differences before and after the protest, across each specification and bandwidth. Full results tables can be found in section 2 of the supplementary materials. 

Across the board, respondents interviewed after the protest have higher presidential trust and approval, rising by around 0.15 to 0.25 on a 4 point response scale. If our assumptions hold, this suggests that the protest had a *positive* overall effect on government support, despite it sharing pro-opposition messages about government incompetence. Our effects are substantively quite large. Using the full sample, estimates are equivalent to a 22% standard deviation in either outcome, or a 12% increase on the pre-period (control group) mean. Reassuringly, effects are also stable across specifications. While the precision of our estimates rises as we increase the sample size, and thus statistical power, our point estimates remain broadly unchanged across the board. The take-home from these models is clear: the protests in Ghana significantly increased support for the incumbent.

\medskip 

```{r results-baseline-trust-and-approval, fig.width=8, fig.height=4, fig.cap = "Main UESD specifications, presenting the impact of the Julorbi House protests on Presidential trust and approval. All models include region fixed effects, while covariate and entropy specifications account for age, gender, education, and urbancy. Bars represent 95% (thick) and 90% (thin) confidence intervals respectively. Number of observations are taken from baseline specifications on trust, and are marginally lower for specifications with additional controls. Collectively, the results suggest that respondents interviewed after the protest were more trusting and approving of the President."}

data <- data %>% mutate(bono = as.factor(bono))

#### 2 day bandwidth (N=336)

julorbi1.1 <- feols(c(trust_pres, performance_pres) ~ postJulorbi2days + bono, 
                    data=data) ## Baseline
julorbi1.2 <- feols(c(trust_pres, performance_pres) ~ postJulorbi2days + 
                      vote2020_inc + age + remittance_quota + 
                      gender + education + urbrur + urbrur_from + bono, data=data) ## Covariates
julorbi1.3 <- feols(c(trust_pres, performance_pres) ~ postJulorbi2days + bono, 
                    data=data_eb_2days, weights=~weights) # Entropy weights



#### 3 day bandwidth (N=508)

julorbi2.1 <- feols(c(trust_pres, performance_pres) ~ postJulorbi3days + bono, 
                    data=data)
julorbi2.2 <- feols(c(trust_pres, performance_pres) ~ postJulorbi3days + 
                      vote2020_inc + age + remittance_quota + 
                      gender + education + urbrur + urbrur_from + bono, data=data)
julorbi2.3 <- feols(c(trust_pres, performance_pres) ~ postJulorbi3days + bono, 
                    data=data_eb_3days, weights=~weights)


#### Full sample excl. protest days (N=627)

julorbi3.1 <- feols(c(trust_pres, performance_pres) ~ postJulorbi_donut + bono, 
                    data=data) 
julorbi3.2 <- feols(c(trust_pres, performance_pres) ~ postJulorbi_donut + 
                      vote2020_inc + age + remittance_quota + 
                      gender + education + urbrur + urbrur_from + bono, data=data) 
julorbi3.3 <- feols(c(trust_pres, performance_pres) ~ postJulorbi_donut + bono, 
                    data=data_eb_fullsample_donut, weights=~weights) 

#### Full sample (N=796)

julorbi4.1 <- feols(c(trust_pres, performance_pres) ~ postJulorbi + bono, 
                    data=data) 
julorbi4.2 <- feols(c(trust_pres, performance_pres) ~ postJulorbi + 
                      vote2020_inc + age + remittance_quota + 
                      gender + education + urbrur + urbrur_from + bono, data=data) 
julorbi4.3 <- feols(c(trust_pres, performance_pres) ~ postJulorbi + bono, 
                    data=data_eb_fullsample, weights=~weights)


uesd_results_main <- c(julorbi1.1, julorbi1.2, julorbi1.3, 
                       julorbi2.1, julorbi2.2, julorbi2.3,
                       julorbi3.1, julorbi3.2, julorbi3.3,
                       julorbi4.1, julorbi4.2, julorbi4.3)

## Collate dataset

julorbi_trust_df <- map_df(uesd_results_main, broom::tidy, .id="model") %>%
  filter(term %in% c("postJulorbi2days", "postJulorbi3days", "postJulorbi", "postJulorbi_donut")) %>%
  mutate(conf.low95 = estimate - 1.96*std.error,
         conf.high95 = estimate + 1.96*std.error,
         conf.low90 = estimate - 1.68*std.error,
         conf.high90 = estimate + 1.68*std.error,
         outcome = rep(c("Trust", "Approval"), 12),
         group = ifelse(term == "postJulorbi", "Full sample ex. first protest day\n(N=802)", 
                 ifelse(term == "postJulorbi_donut", "Full sample ex. all protest days\n(N=632)", 
                 ifelse(term == "postJulorbi3days", "+/-3 days \n(N=515)", 
                        "+/-2 days \n(N=343)"))), 
         spec = rep(c("Baseline", "Baseline", 
                      "Covariates", "Covariates",
                      "Entropy balancing", "Entropy balancing"), 4)) 


### Plot results

ggplot(julorbi_trust_df, aes(y=outcome, x=estimate, col=spec)) +
  facet_wrap(~factor(group,
                     levels = c("+/-2 days \n(N=343)", 
                                "+/-3 days \n(N=515)",
                                "Full sample ex. all protest days\n(N=632)", 
                                "Full sample ex. first protest day\n(N=802)")),
              scales="fixed", nrow=1) +
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low90, xmax=conf.high90, height=0, width=0),
                 size=0.7,
                 position = position_dodge(width=0.5)) +
  geom_errorbarh(aes(xmin=conf.low95, xmax=conf.high95, height=0, width=0),
                 position = position_dodge(width=0.5), 
                 alpha=0.5) +
  geom_point(position = position_dodge(width=0.5), 
             aes(shape = spec, col = spec)) +
  scale_colour_manual(values = c("black", "darkorange", "darkblue")) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(), 
        axis.title.y = element_blank()) +
  xlab("Difference pre/post (1-4 scale)") +
  ggtitle("Presidential trust and approval rise after the protest") +
  labs(subtitle = "Source: Author survey in Ghana")

```

\bigskip 


# Robustness {#robustness}

Before unpacking these results we turn to the robustness of our findings, considering a range of threats to identification. Our research design rests on two families of assumption; that the protest is *excludable* from other events, and that its timing is *ignorable* with respect to potential outcomes. We assess these with a range of supplementary analyses and placebo tests, using both alternative outcomes and data from previous points in time. Our main findings remain robust across the board, instilling confidence that they yield *causal* interpretation.

## Excludability

The first set of assumptions rest on the *excludability* of the Julorbi House protest - that "*any difference between respondents interviewed before and after the event shall be the sole consequence of the event*" [@munoz2020]. 

One threat to this assumption is the presence of *simultaneous events*, which co-vary with the protest and thus confound its impact. Another is when event timing is *endogenous* - if the protests were strategically held on a particular day related to the outcomes we study. The Julorbi protests (and our survey fieldwork) took place in an otherwise quiet period, with the next presidential election more than a year away and no significant news from party primaries, or wider corruption or economic scandals, emerging at the time. One concern, though, is that the first day of protests coincided with a public holiday commemorating Dr. Kwame Nkrumah, Ghana's independence leader.^[This is "endogeneous", insofar as organizers deliberately chose this date to maximize turnout.] The significance of this holiday has declined in recent years, with the government launching an alternative in August, dedicating attention to all of Ghana's "big six" founding fathers.^[The government designated a larger public holiday for the 4th August [@boateng2017], in place since 2019. This "founders' day" seeks to celebrate all of Ghana's "big six", while the September holiday focuses solely on Nkrumah. More state resources and attention are dedicated to the August holiday, including public lectures and education campaigns by prominent public intellectuals and traditional leaders [@nyabor2020; @nunoo2020].] But if the day itself prompts positive evaluations of the government, this might confound the impact of the protest. For instance, the holiday might prime a general sense of national pride, or cause the public to positively benchmark Ghanaian democracy against colonial rule.

We rule out this possibility with a *placebo population test* [@eggersforthcoming], running our UESD design using data from round 7 of the Afrobarometer social survey in Ghana. This was fielded in September 2017, covering very similar calendar dates but across a wider set of outcomes. We test the direct effect of the public holiday, which occurs on the same date every year, but *absent* the impact of a large protest. Figure \@ref(fig:AB-placebo-models-baseline) presents the results, with full tables and more detailed discussion in section 5 of the supplementary materials. On average, Nkrumah Memorial Day has no impact on national identification, nor trust/approval in the President.^[Unfortunately we do not ask questions about national and ethnic identities in our 2023 survey, so cannot test this in our main specifications.] This offers indicative support that our 2023 estimates stem from the Julorbi House protest and *not* its coincidence with the national holiday.

\medskip

```{r AB-placebo-models-baseline, fig.height=4, fig.width=8, fig.cap = "Placebo UESD specifications using round 7 Afrobarometer data (September 2017). Estimates use same specifications as in the main text, but with different data. Bars represent 95% (thick) and 90% (thin) confidence intervals respectively. The results indicate that Nkrumah Memorial day has no signficant impact on national identity, or support for the President."}


## 2 days
ab1.1 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN2days + i(region), data=r7sub)
ab1.2 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN2days + age + gender + remittances_bin + 
        vote2016_inc + education + urbrur + urbrur_from + i(region), data=r7sub)
ab1.3 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN2days  + i(region), data=data_eb_ab_2days, weights = ~weights)

## 3 days
ab2.1 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN3days  + i(region), data=r7sub)
ab2.2 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN3days  + age + gender + remittances_bin + 
        vote2016_inc + education + urbrur + urbrur_from + i(region), data=r7sub)
ab2.3 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN3days  + i(region), data=data_eb_ab_3days, weights = ~weights)

## 4 days
ab3.1 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN4days  + i(region), data=r7sub)
ab3.2 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN4days  + age + gender + remittances_bin + 
        vote2016_inc + education + urbrur + urbrur_from + i(region), data=r7sub)
ab3.3 <- feols(c(ethnic_salience, trust_pres, performance_pres) ~ postKN4days  + i(region), data=data_eb_ab_4days, weights = ~weights)



ab_list <- c(ab1.1, ab1.2, ab1.3,
                ab2.1, ab2.2, ab2.3,
                ab3.1, ab3.2, ab3.3)

ab_main_df <- map_df(ab_list, broom::tidy, .id="model") %>%
  filter(term %in% c("postKN2days", "postKN3days", 
                     "postKN4days", "postKN")) %>%
  mutate(conf.low95 = estimate - 1.96*std.error,
         conf.high95 = estimate + 1.96*std.error,
         conf.low90 = estimate - 1.68*std.error,
         conf.high90 = estimate + 1.68*std.error,
         outcome = c(rep(c("National ID", "Trust", "Approval"), 9)),
         group = ifelse(term == "postKN2days", "+/-2 days \n(N=419)", 
                 ifelse(term == "postKN4days", "+/-4 days\n(N=718)", 
                 ifelse(term == "postKN3days", "+/-3 days \n(N=598)", NA))), 
         spec = rep(rep(c("Baseline", "Covariates", "Entropy balancing"), each=3), 3)) 



ggplot(ab_main_df, aes(y=factor(outcome,
                                levels = c("Approval", 
                                           "Trust", 
                                           "National ID")), x=estimate, col=spec)) +
  facet_wrap(~factor(group,
                     levels = c("+/-2 days \n(N=419)", 
                                "+/-3 days \n(N=598)",
                                "+/-4 days\n(N=718)", 
                                "Full sample ex. KN day\n(N=1824)")),
              scales="fixed", nrow=1) +
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low90, xmax=conf.high90, height=0, width=0),
                 size=0.7,
                 position = position_dodge(width=0.5)) +
  geom_errorbarh(aes(xmin=conf.low95, xmax=conf.high95, height=0, width=0),
                 position = position_dodge(width=0.5), 
                 alpha=0.5) +
  geom_point(position = position_dodge(width=0.5), 
             aes(shape = spec, col = spec)) +
  scale_colour_manual(values = c("black", "darkorange", "darkblue")) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(), 
        axis.title.y = element_blank()) +
  xlab("Difference pre/post") +
  ggtitle("No shift in nationalism or Presidential support after Nkrumah day") +
  labs(subtitle = "Source: Afrobarometer R7 in Ghana (September 2017)")


```

Another potential threat to excludability is the presence of *collateral events*, whereby UESD effects are driven by an event's direct consequences and not the event itself. In the context of a protest, this stems from difficulties disentangling events themselves from how the government responds to them. We do not see cause for concern in our design. While the Julorbi House protest was salient and involved many people, the government response was not especially informative for the public. There was no widespread violence or police brutality, which have drawn negative responses in other African countries.^[For instance, @curtice2021 shows that trust in the police fell in Uganda after selective, heavy-handed management of tax protests.] And unlike authoritarian regimes, where merely permitting a protest to occur is sometimes viewed as a positive signal, protests are common in Ghana and free speech laws are broadly protected. 

Nonetheless, to assuage these concerns we re-run our analysis across a range of alternative and placebo outcomes. We present these in section 5 of the supplementary materials, with three main results. First, we show that support for government performance generally rises only for things directly related to the protest. In particular, perceptions of how the government has handled inflation and corruption, both key to the protest's motivation, increase. For healthcare, education and the general economy, there are more muted effects. Second, we suggest that trust spills over into some, but not all, other domains of government. Trust in government officials, parliament, and the electoral commission all rise in the post-protest period, but there are mixed effects for trust in the police. This makes it unlikely that our main effects - for trust and approval of the President - are driven by police responses to the protest. Third, we study placebo outcomes which we would not obviously expect to be impacted by the protest. Contrary to the effects for the President, we find no impact on measures of social trust - that is, in one's relatives, neighbors, or others. These questions use identical wordings and outcome scales, simply applied to different groups. 

A final excludability concern is whether findings are driven by *unrelated time trends* in the data. This is ultimately an empirical question, and we follow best practice by: a) running a placebo test which splits the control group at its empirical mean: and b), controlling for a respondent's (linearised) interview date in the analysis. The placebo test yields null findings across the board, while at wider bandwidths our results are not sensitive to controlling for the interview date.^[At narrower bandwidths results are sensitive, but this is likely because of the small number of individual days (2 or 3) in the pre/post period.] We present these results in section 4 of the supplementary materials.


## Ignorability {#ignorability}

The second set of assumptions rest on treatment *ignorability*: whether an individual was interviewed before or after the protest is independent of their potential outcomes. The clearest test for this assumption is the extent to which groups are *balanced on observable characteristics*. We showed evidence of this in section \@ref(uesd), with respondents before and after the protest sharing a similar age, gender, education level, and vote choice in the previous election. There was imbalance in urbancy, and slight differences in education at some bandwidths, due to sampling logistics. As a result, we present results that account for a suite of demographic characteristics, and also adjust for region fixed effects in all specifications. Our models thus rely on a weaker assumption of *conditional* ignorability, which is more defensible in this context. 

It is also possible that treatment assignment varies across *unobservable* characteristics. There are a few common ways in which this might impact UESD designs, none of which pose serious problems in our study. One such concern is *reachability* - whether some respondents are harder for enumerators to reach, and are hence more likely to be interviewed later in fieldwork, after the event. This is usually a problem if "*sampled units have any possibility to opt into the survey at different points in time*" [@munoz2020]. In our pre-registered survey design, however, this is not a possibility. Survey enumerators visit one randomly selected enumeration area per day, and sample respondents through a random walk procedure to fit a quota without an option for call-backs.^[In a small number of cases, logistical constraints meant it took more than one day to complete interviews in an enumeration area. Under such circumstances, enumerators were given strict instructions to continue the random walk procedure and *not* revisit individuals who were previously unavailable.] While certain types of respondent may be harder to find and are more likely to be interviewed later in the day, these differences will not span multiple days and so cannot confound the incidence of the Julorbi protest treatment. 

Another concern is *attrition* - if non-response to our outcomes of interest, or non-participation in the survey, becomes more or less likely after the protest for some types of respondent. Our design does not encounter such concerns; there are only a handful of non-responses to the main outcome questions (N = 4 and 12 for trust and approval respectively), so this cannot be driving our estimates. We consider a more nuanced form of *partisan* attrition in section \@ref(mechanisms).

A further concern regards *compliance* - some respondents interviewed in the treatment period may have had no knowledge of the protest, and so it cannot be driving support for the government in the post-treatment period. This is unlikely to be a problem. Ghana has very strong radio and mobile phone penetration, even in remote rural areas, alongside a vibrant civil society in which political discussion is prevalent [@brierley2020]. Given the salience of the protest, the vast majority of respondents to our survey will have heard about it through at least one of these channels.

Empirically, we address compliance concerns in section 4 of the supplementary materials. First, we re-run our main specification for those who report regularly using social media or discussing politics with friends and family. These measures proxy an individual's exposure to information about the protest. The effects are positive for both groups, though tend to be substantively larger for more exposed individuals.^[We note, however, that our "low" discussion and social media groups likely under-estimate exposure to the protest, because we do not have questions about radio access - a key medium of political information in Ghana - in our survey.] Second, we present separate results for our two regions and find similarly positive effects in both. 

Finally, particular care is required in UESDs to not induce *post-treatment bias*. Controlling for variables impacted by the protest risks severely biasing our main estimates. As such, we are cautious to control only for "static" demographic controls (e.g. age, gender, education, urbancy) and use measures of vote choice in the *previous* election, rather than voter intention for the next.

# Mechanisms

Our analysis so far provides robust evidence that the Occupy Julorbi House protest increased government support in Ghana. What explains this result? Given we study an anti-government protest, which brings attention to important governance failures, we might instead anticipate a decline in incumbent trust and approval. Our positive effects thus raise the question as to *who* experiences this uplift. Given Ghana's strong two party system and polarized political context, one possibility is that partisan divides are shaping responsiveness to the protest. 

To explore this further, we examine whether our overall effects mask heterogeneity between supporters of different parties. We split respondents by how they voted in the last general election, categorizing government voters as those who voted for the then incumbent New Patriotic Party (NPP), and opposition supporters as those voting for any other party. In the supplementary materials, we also present results for those who cannot recall which party they voted for but did vote in the election, and those who did not vote at all.^[Among the latter two groups it is difficult to discern political preferences, and thus unclear how to interpret effect heterogeneity.]

We opt for a measure of past voting behavior for two reasons. First, we do not explicitly measure partisanship or its intensity in our survey, as this outcome was less relevant to our original, pre-registered research questions. Second, responses to our past vote choice measure are less likely to change following the protest, reducing concerns about post-treatment bias. 

Before proceeding, we consider how this analysis may raise new concerns about reachability. Past vote choice is itself generally balanced in the pre and post protest period, as we saw in section \@ref(uesd), but it is possible that the *types* of government or opposition voters themselves differ over time. For instance, the protest may prompt a sense of embarrassment for the government's supporters, leaving only the most enthusiastic willing to be interviewed after the protest. 

We run several additional tests to guard against this possibility. First, we run fresh balance tests *within* each voter subgroup. While we do not ask questions about the intensity of party support in our survey, we can nonetheless look to the demographic composition of each sub-sample. Figure \@ref(fig:partisan-characteristics-pre-post) presents the results, with full estimates at other bandwidths in the supplementary materials. As with the full sample, there are some differences in urbancy and education which vary between region. Overall, however, the composition of each voter sub-group does appear broadly comparable. Second, in section 4.6 of the supplementary materials we use Afrobarometer data to validate our measure of partisan support, showing its strong correlation with voting behaviour. We also use constituency election returns to identify government stronghold areas, and show that government-supporting individuals in these areas do not disproportionately drive our main findings.

```{r partisan-characteristics-pre-post, fig.width=8, fig.height=4, fig.cap = "Covariate balance tests for partisan subgroups, before and after the Julorbi House protests."}

## Check whether partisans before/after share comparable characteristics
## i.e. guard against risk that "really strong" partisans are just more likely to take part afterwards

data_npp <- data %>% filter(vote2020_inc == "Govt") 
data_ndc <- data %>% filter(vote2020_inc == "Opp") 

### Balance checks

data_bal_npp <- data_npp %>% mutate(postJulorbi_donut = ifelse(duringJulorbi == 1, NA, postJulorbi),
                        GA = ifelse(region == "Greater Accra", 1, 0),
                        bono = ifelse(region == "Bono", 1, 0)) %>%
  mutate(age_std = as.numeric(scale(age)),
         male_bin = ifelse(gender == "Male", 1, 0),
         urbrur_bin = ifelse(urbrur == "Urban", 1, 0), 
         urbrur_from_bin = ifelse(urbrur_from == "Urban", 1, 0),
         education_none = ifelse(education == "None", 1, 0),
         education_school = ifelse(education %in% c("Primary", "Secondary"), 1, 0),
         education_university = ifelse(education == "University", 1, 0))

data_bal_ndc <- data_ndc %>% mutate(postJulorbi_donut = ifelse(duringJulorbi == 1, NA, postJulorbi),
                        GA = ifelse(region == "Greater Accra", 1, 0),
                        bono = ifelse(region == "Bono", 1, 0)) %>%
  mutate(age_std = as.numeric(scale(age)),
         male_bin = ifelse(gender == "Male", 1, 0),
         urbrur_bin = ifelse(urbrur == "Urban", 1, 0), 
         urbrur_from_bin = ifelse(urbrur_from == "Urban", 1, 0),
         education_none = ifelse(education == "None", 1, 0),
         education_school = ifelse(education %in% c("Primary", "Secondary"), 1, 0),
         education_university = ifelse(education == "University", 1, 0))

## More urban areas interviewed *after*, likely due to regional sampling strategies
## But on individual-level characteristics there's no meaningful difference

data_bal_npp_bono <- data_bal_npp %>% filter(region == "Bono")
data_bal_npp_ga <- data_bal_npp %>% filter(region != "Bono")
data_bal_ndc_bono <- data_bal_ndc %>% filter(region == "Bono")
data_bal_ndc_ga <- data_bal_ndc %>% filter(region != "Bono")

### Government voters

balance1_npp_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi, data=data_bal_npp_ga)

balance2_npp_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi_donut, data=data_bal_npp_ga)

balance3_npp_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi3days, data=data_bal_npp_ga)

balance4_npp_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi2days, data=data_bal_npp_ga)

balance1_npp_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi, data=data_bal_npp_bono)

balance2_npp_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi_donut, data=data_bal_npp_bono)

balance3_npp_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi3days, data=data_bal_npp_bono)

balance4_npp_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi2days, data=data_bal_npp_bono)


### Opposition voters

balance1_ndc_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi, data=data_bal_ndc_ga)

balance2_ndc_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi_donut, data=data_bal_ndc_ga)

balance3_ndc_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi3days, data=data_bal_ndc_ga)

balance4_ndc_ga <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi2days, data=data_bal_ndc_ga)

balance1_ndc_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi, data=data_bal_ndc_bono)

balance2_ndc_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi_donut, data=data_bal_ndc_bono)

balance3_ndc_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi3days, data=data_bal_ndc_bono)

balance4_ndc_bono <- feols(c(age_std, remittance_quota, male_bin,
        education_none, education_school, education_university,
        urbrur_bin, urbrur_from_bin
        ) ~ postJulorbi2days, data=data_bal_ndc_bono)


## Make tables

## Make graph

balance_list <- c(balance1_npp_ga, balance2_npp_ga, balance3_npp_ga, balance4_npp_ga,
                  balance1_npp_bono, balance2_npp_bono, balance3_npp_bono, balance4_npp_bono,
                  balance1_ndc_ga, balance2_ndc_ga, balance3_ndc_ga, balance4_ndc_ga, 
                  balance1_ndc_bono, balance2_ndc_bono, balance3_ndc_bono, balance4_ndc_bono)

balance_df <- map_df(balance_list, broom::tidy, .id="model") %>%
  filter(term != "(Intercept)") %>%
  mutate(conf.low = estimate - 1.96*std.error,
         conf.high = estimate + 1.96*std.error,
         sample = ifelse(term == "postJulorbi", "Full ex. first protest day", 
                  ifelse(term == "postJulorbi_donut", "Full ex. all protest days", 
                  ifelse(term == "postJulorbi3days", "3 day bandwidth pre/post", 
                         "2 day bandwidth pre/post"))),
         outcome = rep(c("Age", "Remittances",
                         "Gender (male)", 
                         "No formal\neducation", "Primary or\nsecondary", 
                         "University",
                         "Urban", 
                         "Born urban"), 16), 
         party = rep(c("Government voters (N=275)", "Opposition voters (N=247)"), each=64), 
         region = rep(c("Greater Accra", "Bono", "Greater Accra", "Bono"), each=32)) %>%
  filter(sample == "Full ex. first protest day")

bal2 <- ggplot(data=balance_df, aes(x = estimate, 
                                    y = factor(outcome,
                                               levels = c(
                                               "Urban",
                                               "Born urban",
                                               "No formal\neducation",
                                               "Primary or\nsecondary",
                                               "University",
                                               "Gender (male)",
                                               "Remittances",
                                               "Age")))) +
  facet_wrap(~factor(party, 
                     levels = c("Opposition voters (N=247)",
                                "Government voters (N=275)"))) + 
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low, xmax=conf.high, height=0, width=0, col=region),
                 position = position_dodge(width=0.5)) +
  geom_point(position = position_dodge(width=0.5), alpha=0.7, 
             aes(col=region, shape = region)) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(),
        axis.title.y = element_blank()) +
  xlab("Difference before/after protest") +
  ggtitle("Voter subgroups are demographically similar before/after the protest") +
  scale_x_continuous(limits = c(-0.6, 0.65)) +
  scale_colour_manual(values = c("darkorange", "darkblue"))

bal2

```

With these tests in mind, we next interact our measure of past vote choice with a pre/post protest dummy and present marginal effects in Figure \@ref(fig:results-partisanship). The findings are presented with the full sample, but are similar at other bandwidths and are presented in section 3 of the supplementary materials. Compared with other opposition voters, we find that government supporters respond most positively to the protest. Presidential trust and approval rises by around 0.6 on a 4 point scale, more than double the aggregate effect size in section \@ref(mainresultsplot). The difference between with opposition voters, who exhibit null effects, is itself statistically significant [@gelman2006].

```{r results-partisanship, fig.height=4, fig.width=8, fig.cap = "Main UESD specifications by 2020 general election vote choice. All models include region fixed effects, while covariate and entropy specifications account for age, gender, education, and urbancy. Bars represent 95% (thick) and 90% (thin) confidence intervals respectively. Number of observations are taken from baseline specifications on trust, and are marginally lower for specifications with additional variables. Collectively, the results suggest that positive trust and approval effects observed after the protests are driven by government supporters."}

### Run specifications

data <- data %>% mutate(vote2020_inc = ifelse(is.na(vote2020_inc) == TRUE, 
                                              "Non-voter", vote2020_inc))

###### Trust

## 2 days
partisan1.1 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi2days) + vote2020_inc + bono, data=data) ## Baseline

partisan1.2 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi2days) + vote2020_inc + age + remittance_quota + 
                      gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan1.3 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi2days) + 
                       vote2020_inc + bono, 
                     data=data_eb_2days, weights=~weights) 

## 3 days
partisan2.1 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi3days) + 
                       vote2020_inc + bono, data=data) ## Baseline

partisan2.2 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi3days) + 
                       vote2020_inc + age + remittance_quota + 
                      gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan2.3 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi3days) + 
                       vote2020_inc + bono, 
                     data=data_eb_3days, weights=~weights) 

## Full (ex protest days)
partisan3.1 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi_donut) + 
                       vote2020_inc + bono, data=data) ## Baseline

partisan3.2 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi_donut) + 
                       vote2020_inc + age + remittance_quota + 
                       gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan3.3 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi_donut) + 
                       vote2020_inc + bono, 
                     data=data_eb_fullsample_donut, weights=~weights) 

## Full
partisan4.1 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi) + 
                       vote2020_inc + bono, data=data) ## Baseline

partisan4.2 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi) + 
                       vote2020_inc + age + remittance_quota + 
                       gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan4.3 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi) + 
                       vote2020_inc + bono, 
                     data=data_eb_fullsample, weights=~weights) 


###### Approval

## 2 days
partisan5.1 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi2days) + 
                       vote2020_inc + bono, data=data) ## Baseline

partisan5.2 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi2days) + 
                       vote2020_inc + age + remittance_quota + 
                       gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan5.3 <- feols(trust_pres ~ i(vote2020_inc, postJulorbi2days) + 
                       vote2020_inc + bono, 
                     data=data_eb_2days, weights=~weights)

## 3 days
partisan6.1 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi3days) + 
                       vote2020_inc + bono, data=data) ## Baseline

partisan6.2 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi3days) + 
                       vote2020_inc + age + remittance_quota + 
                       gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan6.3 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi3days) + 
                       vote2020_inc + age + remittance_quota + 
                       gender + education + 
                       urbrur + urbrur_from + 
                       bono, 
                     data=data_eb_3days, weights=~weights) 

## Full (ex protest days)

partisan7.1 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi_donut) + 
                       vote2020_inc + bono, data=data) ## Baseline

partisan7.2 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi_donut) + 
                       vote2020_inc + age + remittance_quota + 
                       gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan7.3 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi_donut) + 
                       vote2020_inc + bono, 
                     data=data_eb_fullsample_donut, weights=~weights) 

## Full
partisan8.1 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi) + 
                       vote2020_inc + bono, data=data) ## Baseline

partisan8.2 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi) + 
                       vote2020_inc + age + remittance_quota + 
                       gender + education + 
                       urbrur + urbrur_from + 
                       bono, data=data) ## With wider covariates

partisan8.3 <- feols(performance_pres ~ i(vote2020_inc, postJulorbi) + 
                       vote2020_inc + bono, 
                     data=data_eb_fullsample, weights=~weights) 

## Make graphs (seperate for each bandwidth)

julorbi_partisan_list <- list(partisan1.1, partisan1.2, partisan1.3,
                              partisan2.1, partisan2.2, partisan2.3,
                              partisan3.1, partisan3.2, partisan3.3,
                              partisan4.1, partisan4.2, partisan4.3,
                              partisan5.1, partisan5.2, partisan5.3,
                              partisan6.1, partisan6.2, partisan6.3,
                              partisan7.1, partisan7.2, partisan7.3,
                              partisan8.1, partisan8.2, partisan8.3)

julorbi_partisan_df <- map_df(julorbi_partisan_list, broom::tidy, .id="model") %>%
  filter(term %in% c("vote2020_inc::Non-voter:postJulorbi2days",
                     "vote2020_inc::DKs:postJulorbi2days",
                     "vote2020_inc::Opp:postJulorbi2days",
                     "vote2020_inc::Govt:postJulorbi2days",
                     "vote2020_inc::Non-voter:postJulorbi3days",
                     "vote2020_inc::DKs:postJulorbi3days",
                     "vote2020_inc::Opp:postJulorbi3days",
                     "vote2020_inc::Govt:postJulorbi3days",
                     "vote2020_inc::Non-voter:postJulorbi_donut",
                     "vote2020_inc::DKs:postJulorbi_donut",
                     "vote2020_inc::Opp:postJulorbi_donut",
                     "vote2020_inc::Govt:postJulorbi_donut",
                     "vote2020_inc::Non-voter:postJulorbi",
                     "vote2020_inc::DKs:postJulorbi",
                     "vote2020_inc::Opp:postJulorbi",
                     "vote2020_inc::Govt:postJulorbi")) %>%
  mutate(conf.low95 = estimate - 1.96*std.error,
         conf.high95 = estimate + 1.96*std.error,
         conf.low90 = estimate - 1.68*std.error,
         conf.high90 = estimate + 1.68*std.error,
         outcome = c(rep("Trust", 48), rep("Approval", 48)),
         group = rep(c(rep("+/-2 days \n(N=343)", 12),
                   rep("+/-3 days \n(N=515)", 12),
                   rep("Full sample (ex. protest days)\n(N=632)", 12), 
                   rep("Full sample\n(N=802)", 12)), 2), 
         spec = rep(c("Baseline", "Baseline", "Baseline", "Baseline",
                      "Covariates", "Covariates", "Covariates", "Covariates",
                      "Entropy balancing", "Entropy balancing", "Entropy balancing", "Entropy balancing"), 8), 
         party = rep(c("Don't know vote",
                       "Government voter",
                       "Non-voter", 
                       "Opposition voter"), 24))

partisan_df1 <- julorbi_partisan_df %>% filter(group == "+/-2 days \n(N=343)")
partisan_df2 <- julorbi_partisan_df %>% filter(group == "+/-3 days \n(N=515)")
partisan_df3 <- julorbi_partisan_df %>% filter(group == "Full sample (ex. protest days)\n(N=632)")
partisan_df4 <- julorbi_partisan_df %>% filter(group == "Full sample\n(N=802)")

## Plot each spec (one for now, others saved for SM)

partisan_plot1 <- ggplot(partisan_df1, aes(y=outcome, x=estimate, col=spec)) +
  facet_wrap(~party,
              scales="fixed", nrow=1) +
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low90, xmax=conf.high90, height=0, width=0),
                 size=0.7, position = position_dodge(width=0.5)) +
  geom_errorbarh(aes(xmin=conf.low95, xmax=conf.high95, height=0, width=0),
                 position = position_dodge(width=0.5), 
                 alpha=0.5) +
  geom_point(position = position_dodge(width=0.5), 
             aes(shape = spec, col = spec)) +
  scale_colour_manual(values = c("black", "grey40", "darkred")) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(), 
        axis.title.y = element_blank()) +
  xlab("Difference pre/post (1-4 scale)") +
  ggtitle("Trust and approval effects driven by Government supporters") +
  labs(subtitle = "2 day bandwidth (N=343)")

partisan_plot2 <- ggplot(partisan_df2, aes(y=outcome, x=estimate, col=spec)) +
  facet_wrap(~party,
              scales="fixed", nrow=1) +
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low90, xmax=conf.high90, height=0, width=0),
                 size=0.7, position = position_dodge(width=0.5)) +
  geom_errorbarh(aes(xmin=conf.low95, xmax=conf.high95, height=0, width=0),
                 position = position_dodge(width=0.5), 
                 alpha=0.5) +
  geom_point(position = position_dodge(width=0.5), 
             aes(shape = spec, col = spec)) +
  scale_colour_manual(values = c("black", "grey40", "darkred")) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(), 
        axis.title.y = element_blank()) +
  xlab("Difference pre/post (1-4 scale)") +
  ggtitle("Trust and approval effects driven by Government supporters") +
  labs(subtitle = "3 day bandwidth (N=515)")

partisan_plot3 <- ggplot(partisan_df3, aes(y=outcome, x=estimate, col=spec)) +
  facet_wrap(~party,
              scales="fixed", nrow=1) +
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low90, xmax=conf.high90, height=0, width=0),
                 size=0.7, position = position_dodge(width=0.5)) +
  geom_errorbarh(aes(xmin=conf.low95, xmax=conf.high95, height=0, width=0),
                 position = position_dodge(width=0.5), 
                 alpha=0.5) +
  geom_point(position = position_dodge(width=0.5), 
             aes(shape = spec, col = spec)) +
  scale_colour_manual(values = c("black", "grey40", "darkred")) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(), 
        axis.title.y = element_blank()) +
  xlab("Difference pre/post (1-4 scale)") +
  ggtitle("Trust and approval effects driven by Government supporters") +
  labs(subtitle = "Full sample ex. protest days (N=632)")

partisan_df5 <- partisan_df4 %>% filter(party %in% c("Opposition voter", 
                                                     "Government voter"))

partisan_plot4 <- ggplot(partisan_df5, aes(y=outcome, x=estimate, col=spec)) +
  facet_wrap(~factor(party,
                     levels = c("Opposition voter", 
                                "Government voter")), scales="fixed", nrow=1) +
  theme(panel.border = element_rect(colour = "black", fill = NA)) +
  geom_vline(xintercept=0, linetype=2) +
  geom_errorbarh(aes(xmin=conf.low90, xmax=conf.high90, height=0, width=0),
                 size=0.7, position = position_dodge(width=0.5)) +
  geom_errorbarh(aes(xmin=conf.low95, xmax=conf.high95, height=0, width=0),
                 position = position_dodge(width=0.5), 
                 alpha=0.5) +
  geom_point(position = position_dodge(width=0.5), 
             aes(shape = spec, col = spec)) +
  scale_colour_manual(values = c("black", "darkorange", "darkblue")) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(), 
        axis.title.x = element_blank()) +
  xlab("Difference pre/post (1-4 scale)") +
  ggtitle("Trust and approval effects driven by Government voters") +
  labs(subtitle = "Full sample (N=802)") +
  coord_flip()

## Print preferred spec for main text

partisan_plot4

```

What might explain this pattern? One interpretation of these findings rests on the different information the protest sends to different voters, which in turn has a reinforcing effect on their identity. Those aligned to the opposition already have negative prior beliefs about the government, and so the protests do not provide any *new* information on which they can update. In contrast, disillusioned government voters perceive the opposition and the protests as a threat, reinforcing their partisan identity and encouraging them to rally to the incumbent's defense. This can de-emphasize any "soft" disapproval previously held, driven by corruption scandals and the poor macroeconomic climate.

In this sense, the protests in Ghana may have triggered a "*reverse backlash*" [@dennison2023reverse] and heightened partisan identity. The demonstrations were defined explicitly against the government, and so posed a threat to the government's remaining supporters - the excluded out-group [@tajfel1979individuals]. These supporters rallied to the government's defense, and by extension to the identity and interests that it symbolizes. While supporters often have misgivings about particular policies, especially when economic conditions are poor, salient anti-government protests relegate these concerns to the background, and instead prompt a "*partisan rally round the flag*" effect. This is akin to the wider rally effects that have been documented elsewhere, where shock events like terrorist attacks reinforce national pride among in group members [@skocpol2002; @lambert2011] and drive trust in both a country's political institutions and leader of the day [e.g. @hetherington2003;@perrin2009;@geys2017].

Figure \@ref(fig:ceiling-effects) provides some evidence in support of this mechanism. As can be seen, opposition voters are bottomed out before the protest takes place, so have no room to become *even less* satisfied with the government. Meanwhile, incumbent voters have middling levels of support, which appear *soft* given the rapid positive effects among this group in the post-protest period. 

\medskip 

```{r ceiling-effects, fig.width=8, fig.height=4, fig.cap="Trust in President by vote choice, before and after the protest."}

party <- data %>%
  filter(vote2020_inc %in% c("Govt", "Opp")) %>%
  filter(!is.na(postJulorbi)) %>%
  group_by(vote2020_inc, postJulorbi) %>%
  mutate(mean_trust = mean(trust_pres, na.rm=T), 
         vote2020_inc = ifelse(vote2020_inc == "Govt", "Voted Government in 2020", "Voted Opposition in 2020")) %>%
  ungroup() %>%
  select(vote2020_inc, postJulorbi, trust_pres, mean_trust) %>%
  mutate(postJulorbi = ifelse(postJulorbi == "1", "After protest", "Before protest"))

ggplot(data = party, aes(x=trust_pres, 
                         by = factor(postJulorbi), y = after_stat(prop))) +
  geom_bar(aes(fill=factor(postJulorbi,
                           levels = c("Before protest", "After protest"))), 
               col="black", stat="prop", position="dodge") +
  facet_wrap(~factor(vote2020_inc,
                     levels=c("Voted Opposition in 2020", "Voted Government in 2020"))) +
  theme_bw() +
  theme(legend.title=element_blank(), 
        legend.position="bottom") +
  xlab("Trust President (1-4)") + ylab("Proportion") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("orange", "darkblue"))

  

```

# External validity {#externalvalidity}

Our unexpected event in survey design provides evidence that the Julorbi House protests increased government support in Ghana. But a key critique of these designs is that, by identifying short-run causal effects, they fail to generate estimates which are of relevance to a wider set of cases and theoretical frameworks. To address these concerns, we consider three dimensions along which our findings may travel: the generalisability of our survey sample, of Ghana as a comparative country case, and of the protest event itself.  

First, we present evidence that our survey sample is similar to the wider Ghanaian population. In Figure \@ref(fig:survey-external-validity) we compare our key demographic measures with those from round 9 of the Afrobarometer, a nationally representative survey conduced in March 2022. Since half of our sample come from the relatively remote Bono region, our survey is slightly more rural than average. Moreover, given our fieldwork took place after an additional 18 months of economic deterioration, it is not surprising that intended support for the government is slightly lower in our sample. But otherwise, differences between samples are small and indicate that our survey population is sufficiently representative to cautiously generalize.^[One key difference with our survey is our quota system for sampling remittance recipients. Afrobarometer did not ask about this outcome in round 9, but we would expect any demographic or political differences to be picked up by the measures presented.] In section 1 of the supplementary materials, we also compare Afrobarometer respondents in our sampled regions to the rest of the country, and once again find reasonable demographic and political representation.

```{r survey-external-validity, fig.width=8, fig.height=4, fig.cap = "Demographic and political characteristics of author survey sample, compared with a recent nationally representative Afrobarometer survey"}

## Get means and 95% CIs for AB and our survey

AB_r9_means <- AB_r9 %>%
  transmute(`Age (mean)` = mean(age, na.rm=T), 
            `Male` = mean(gender_male, na.rm=T), 
            Urban= mean(urban, na.rm=T),
            `No formal education` = mean(education_none, na.rm=T),
            `Primary or Secondary` = mean(education_school, na.rm=T),
            University = mean(education_uni, na.rm=T),
            `Vote intention (Govt)` = mean(intend_govt, na.rm=T),
            `2020 turnout` = mean(turnout, na.rm=T),
            dataset = "Afrobarometer R9\n(March 2022)") %>%
  slice(1) %>%
  melt()

data_means <- data %>%
  mutate(gender_male = ifelse(gender == "Male", 1, 0), 
         urban = ifelse(urbrur == "Urban", 1, 0),
         education_none = ifelse(education == "None", 1, 0),
         education_school = ifelse(education %in% 
                                     c("Primary", "Secondary"), 1, 0),
         education_uni = ifelse(education == "University", 1, 0),
         turnout = ifelse(vote2020_inc == "Non-voter", 0, 1)) %>%
  transmute(`Age (mean)` = mean(age, na.rm=T), 
            `Male` = mean(gender_male, na.rm=T), 
            Urban= mean(urban, na.rm=T),
            `No formal education` = mean(education_none, na.rm=T),
            `Primary or Secondary` = mean(education_school, na.rm=T),
            University = mean(education_uni, na.rm=T),
            `Vote intention (Govt)` = mean(vote_intention_inc, na.rm=T),
            `2020 turnout` = mean(turnout, na.rm=T),
            dataset = "Author survey\n(September 2023)") %>%
  slice(1) %>%
  melt()

data_exval <- rbind(AB_r9_means, data_means) %>% 
  mutate(value = ifelse(variable == "Age (mean)", value/100, value))

## Make plot

ggplot(data_exval, aes(x=value, y = variable, 
                       col=dataset, 
                       shape = dataset,
                       group = variable)) +
  geom_line(col = "grey20") +
  geom_point(size=1.5) +
  scale_colour_manual(values = c("darkorange", "darkblue")) +
  scale_x_continuous(limits = c(0,1), 
                     breaks = c(0, 0.25, 0.5, 0.75, 1), 
                     labels = c("0", "25", "50", "75", "100")) +
  theme_bw() +
  theme(legend.position = "bottom", 
        legend.title = element_blank(),
        axis.title.y = element_blank()) +
  xlab("Proportion (%) / years (age)")



```

Second, Ghana shares similarities with many other lower-income democracies, both in Africa and beyond. The country sits toward the middle of Africa's income per capita, HDI, and urbanisation distributions. A wide body of work has used the country as a theoretical and empirical base in which to test more general political phenomena, like performance voting, election fraud, clientelism, and ethnic politics [e.g. @weghorst2013; @harding2015; @nathan2019; @asunka2019; @ofosu2019; @brierley2020; @brierley2020a].

One relevant difference, perhaps, is Ghana's two-party system where both major parties have spent significant periods in power [@riedl2014; @stoecker2023partisanship]. This likely aids the development of strong partisan attachments to both ruling and opposition parties, which are less present in dominant party regimes or fragmented party systems [@riedl2012; @mattes2020]. This is a useful scope condition for our findings, which are more likely to travel to contexts like Nigeria, Indonesia, India, or Mexico, where opposition parties are somewhat institutionalized and competitive, than those in which such parties rapidly change shape and form over time.

Lastly, the Occupy Julorbi House protests are reminiscent of many other political demonstrations in lower-income democracies. In such environments, electoral advantages for incumbents tend to be considerable, often operating through control of public media and use of state resources to fund patronage [@bleck2018a]. This leaves protest as an important way to express dissent, and indeed anti-government protests, focused around "valence" issues like economic management, are increasingly common in Sub-Saharan Africa [@harris2019]. 

The Ghanaian case also speaks to debates about how governing elites respond to protest events. While literature on protests in lower-income states focuses overwhelmingly on repression as a policy tool, Ghana, like many lower-income *democracies*, maintains relatively strong protections for free speech and freedom of assembly. This means that its politicians are less able to use repression, and that doing so would reflect a severe aberration from political norms that would likely cause severe backlash from the public. Instead, Ghanaian politicians may well update policy positions and behaviours based on the *perception* that protests matter for public opinion, as has been documented in Europe and the United States [e.g. @hutter2018responds; @wouters2017demonstrating; @barrie2024]. While our findings do not speak to more autocratic countries, where governments routinely use repressive tactics, we do expect them to reflect dynamics across a broader range of lower-income democratic societies, in both Africa and beyond.

# Conclusion {#discussion}

Popular protests and mass demonstrations are on the rise around the world. Discontent with inflation, corruption, and climate change, together with hardening social and economic inequalities, have seen the streets filled with people from the industrialized north to the industrializing south [@barrie2021]. We know a significant amount as to why these protests emerge and why some individuals are more or less likely to participate in them [@finkel1989personal; @chong2014collective]. We also know that protests can prompt politicians to change their behaviour, based on perceptions of what the public thinks [@hutter2018responds; @wouters2017demonstrating; @barrie2024]. But there is minimal evidence as to how public opinion *actually* responds, particularly in lower-income democratic settings. 

We begin to address this gap, by examining the effects of a multi-day anti-government protest in Ghana on incumbent support. The Occupy Julorbi House demonstrations, focused on government incompetence and mismanagement of the economy, occurred in the midst of an independently organised and pre-registered survey which we were already conducting in the country. Using an unexpected event in survey design, we compare survey respondents interviewed immediately before and after the protest to gauge its causal effects [@munoz2020].

Although this protest was largely aimed at government incompetence, our results are contrary to what protesters themselves might have expected. We show that survey respondents interviewed immediately after the demonstration were significantly more trusting and approving of the President, suggesting that an anti-government protest increased government support. When unpacking these results further, we find that this positive effect is largely driven by those who voted for the government in the previous general election, with no notable impact on the attitudes of opposition supporters. We interpret this as a product of the explicit anti-government nature of the protests, which posed a threat to the government's remaining supporters and cause them to rally to its defense. These effects appear to stem more from government voters in competitive, or even opposition held, electoral constituencies, raising questions around the role of one's local social environment in perceptions of partisan identity and group threat [@ichino2013; @nathan2016].

Our findings are in the vein of recent work, which has begun to highlight the importance of protests for shaping the political beliefs and attitudes of the general public [see @barrie2021]. But this work has largely focused on either the US and Western Europe *or* authoritarian contexts, and often struggles to overcome the endogeneity that plagues political participation and the emergence of protests. Our analysis addresses these deficiencies, by applying a quasi-experimental research design to a protest in a lower-income, understudied form of democratic context.

We also add nuance to the mechanisms by which protests shape public opinion. Existing literature highlights the ways protests convey information [e.g., @winters2014partisan] and prime group identities [e.g., @mazumder2018persistent]. Our findings show that these can sometimes operate in conjunction, affecting different groups in different ways at the same time. In our setting, opposition voters discern no new information from the protest, and so have no room to become even less satisfied with government. Government supporters, even those whose support is wavering, can be incentivized to rally behind the incumbent if the protest casts them as an excluded, and threatened, social out-group. 

While our empirical analysis leverages one protest in a single country, there are several reasons to think our findings travel. Ghana shares many similarities with other lower-income democracies, and the Occupy Julorbi House demonstrations are reminiscent of a broader trend toward anti-government, "valence" protests across the continent [@arruda2021protests; @hughes2016protest]. Our findings do require some scoping, particularly with regard to Ghana's *lack* of state repression and it's unusually institutionalised party system [@riedl2014; @stoecker2023partisanship]. But there remain important lessons for a range of other democratic environments, where the results of our analysis might well replicate. 

Lastly, our findings have wider implications for the functioning of accountability in low-capacity, lower-income democracies. In such environments, government performance is often less connected to vote choice [see @grossman2022government], but protests can prompt responsiveness from political elites [@arruda2021protests; @hughes2016protest]. Our results show why this accountability mechanism might sometimes fail. Ghana's poor macroeconomic climate and corruption scandals did not change over the course of our survey, but support for the incumbent rose nonetheless. For the government's past voters, perceived group threats overrode poor evaluations of performance. As protests become increasingly regular around the world, this adds nuance to their role in holding governments to account.   

\clearpage

# Bibliography

<div id="refs"></div>
